package net.chat.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.chat.Forum;
import net.chat.server.ChatServer;
import net.chat.utils.Util;
import net.chat.User;

/**
 * The ForumServlet is used to service requests relating to forums.
 * @author Prabhat
 * Implemented 'create' and 'delete' forum actions in doGet and doPost
 * 24/03/11 Implemented 'getUsers' action which returns updated list of user in forum
 *          Implemented 'leave' action
 * @author Amir added last part in doGet to return updated list of forums
 */
public class ForumServlet extends HttpServlet {

    private ChatServer server = ChatServer.getInstance();

    /**
     * Handles POST requests to create new forum
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String action = request.getParameter("action");
        String redirectUrl = Util.WEBAPP_URL + "stage2/";

        if (action != null && action.equals("create")) {

            // from which page? admin or createforum
            String from = request.getParameter("from");
            redirectUrl += from + ".jsp";

            String name = request.getParameter("fname");
            String category = request.getParameter("fcategory");

            if (name != null && !name.isEmpty()
                    && category != null && !category.isEmpty()) {
                Forum newForum = new Forum(name, category);
                server.newForum(newForum);
                redirectUrl += "?fid=" + newForum.getFid();
            } else {
                redirectUrl += "?err=f";
            }
        }
        response.sendRedirect(redirectUrl);
    }

    /**
     * Handles GET requests to delete forum from admin, allow user to leave forum,
     * and get the list of users in the forum by fid.
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        long timeBefore = new Date().getTime(); // in milliseconds
        String action = request.getParameter("action");
        if (action != null) {
            String redirectUrl = Util.WEBAPP_URL + "stage2/";
            String strFid = request.getParameter("fid");

            if (action.equals("delete")) {
                String from = request.getParameter("from");
                redirectUrl += from + ".jsp";
                server.deleteForum(Integer.parseInt(strFid));
                response.sendRedirect(redirectUrl);
            } else if (action.equals("leave")) {
                redirectUrl += "forums.jsp";
                String strUid = request.getParameter("uid");
                User user = server.getUser(new Integer(strUid).intValue());
                Forum forum = server.getForum(new Integer(strFid).intValue());
                forum.leave(user);
                response.sendRedirect(redirectUrl);
            } else if (action.equals("getUsers")) {

                String t = request.getParameter("timeout");
                int timeout = Util.AJAX_LONG_LIVE_TIMEOUT;
                if (t != null) {
                    timeout = new Integer(t).intValue();
                }
                // add all user ids we have at the client side
                List<Integer> uidsAtClient = new ArrayList<Integer>();
                String strUids = request.getParameter("uids");
                if (strUids != null && !strUids.trim().isEmpty()) {
                    String[] arrUids = strUids.split(",");
                    for (String uid : arrUids) {
                        uidsAtClient.add(new Integer(uid));
                    }
                }
                response.setContentType("text/html;charset=UTF-8");
                PrintWriter out = response.getWriter();

                try {
                    long timeAfter = new Date().getTime(); // in milliseconds
                    long diff = timeAfter - timeBefore;
                    while (true) {
                        timeAfter = new Date().getTime();
                        diff = timeAfter - timeBefore;

                        if (diff > timeout) {
                            out.print("timeout");
                            out.flush();
                            break;
                        }
                        // get updated user ids at the server in this forum
                        List<Integer> uidsAtServer = new ArrayList<Integer>();

                        Forum forum = server.getForum(new Integer(strFid).intValue());
                        List<User> users = forum.getUsers();
                        for (User user : users) {
                            uidsAtServer.add(user.getUid());
                        }

                        // check if client has the same users list as server in this forum
                        if (uidsAtClient.equals(uidsAtServer)) {
                            Thread.sleep(4000); // wait 4 secs then check again
                        } else {
                            //Create the JSON response.
                            /*{"users":
                            {"user":[
                            {"id": "1", "fname": "Prabhat"},
                            {"id": "2", "fname": "Amir"} ]
                            }}*/

                            String json = "{\"users\": {";
                            if (users.size() > 0) {
                                json += "\"user\":[ ";
                                for (Iterator<User> itr = users.iterator(); itr.hasNext();) {
                                    User user = itr.next();
                                    json += "{\"id\":  \"" + user.getUid() + "\", \"fname\": \"" + user.getFname() + "\"}";
                                    if (itr.hasNext()) {
                                        json += ", ";
                                    } else {
                                        json += " ";
                                    }
                                }
                                json += "]";
                            } else {
                                //Send an empty message to avoid a Javascript error when we check for message lenght in the loop.
                                json += "\"user\":[]";
                            }
                            //Close our response
                            json += "}}";

                            out.print(json);
                            out.flush();
                            break;
                        }
                    }
                } catch (InterruptedException ex) {
                    Logger.getLogger(MsgServlet.class.getName()).log(Level.SEVERE, null, ex);
                } finally {
                    out.close();
                }
            }
            return;
        }

        /* Amir code starts from here */

        PrintWriter out = response.getWriter();
        response.setContentType("text/html;charset=UTF-8");
        response.setHeader("Cache-Control", "no-cache");
        ////////////////////////////////////////////////////
        try {
            long timeAfter = new Date().getTime(); // in milliseconds
            long diff = timeAfter - timeBefore;
            String t = request.getParameter("timeout");
            int timeout = new Integer(t).intValue();

            List<Forum> forums;
            String forumsInSess;

            forums = server.getForums();
            System.out.println("request recieved");
            while (true) {
                timeAfter = new Date().getTime();
                diff = timeAfter - timeBefore;

                if (diff > timeout) {
                    System.out.println("timeout");
                    out.print("");
                    out.flush();
                    break;
                }

                forumsInSess = (String) request.getSession().getAttribute(Util.FORUM_LIST_SESS);
                forums = server.getForums();
                if (isChanged(forums, forumsInSess)) {
                    System.out.println("server=" + convertListToStr(forums) + " session =" + forumsInSess);
                    updateSessAndSendForumsToClient(forums, request, out);
                    break;
                }
                // no change, wait a few seconds, enter loop again
                Thread.sleep(1 * 4000);
            }//while
        } //try
        catch (InterruptedException ex) {
            Logger.getLogger(MsgServlet.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            out.close();
        }
    }

    public boolean isChanged(List<Forum> forums, String forumsInSess) {
        return !convertListToStr(forums).equals(forumsInSess);
    }

    private String convertListToStr(List<Forum> forums) {
        StringBuilder strBuilder = new StringBuilder();
        for (Forum f : forums) {
            strBuilder.append(f.getFid() + "," + f.getUsers().size() + ":");
        }
        return strBuilder.toString();
    }

    private void updateSessAndSendForumsToClient(List<Forum> forums, HttpServletRequest rq, PrintWriter out) {

        String forumsInSess = convertListToStr(forums);
        rq.getSession().setAttribute(Util.FORUM_LIST_SESS, forumsInSess);
        String tablehead = getTableHead();
        String tablecontent = "";
        if (forums.size() > 0) {
            // send forums to client
            int i = 0;
            String className = "oddtr";//className="oddtr"|"eventr"
            for (Iterator<Forum> itr = forums.iterator(); itr.hasNext();) {
                ++i;
                if (className.equals("eventr")) {
                    className = "oddtr";
                } else {
                    className = "eventr";
                }
                Forum forum = itr.next();
                tablecontent += "<tr class=\"" + className + "\" id=\"forumno" + Integer.toString(forum.getFid()) + "\">";
                tablecontent += "<td>" + i + "</td>";
                tablecontent += "<td>" + forum.getFid() + "</td>";
                tablecontent += "<td>" + forum.getName() + "</td>";
                tablecontent += "<td>" + forum.getCategory() + "</td>";
                tablecontent += "<td>" + forum.getUsers().size() + "</td>";
                tablecontent += "<td><a href='" + "joinforum.jsp?fid=" + forum.getFid() + "'>join</a></td>";
                tablecontent += "</tr>";
            }

        } else {
            tablecontent += "<tr><td colspan=\"6\">No forums</td></tr>";
        }
        String table = tablehead.replace("##TABLE-CONTENT##", tablecontent);
        table += "<br /><b>" + forums.size() + " forums!</b>";
        out.println(table);
        out.flush();
        System.out.println("Data sent for client");
    }

    private String getTableHead() {
        String table = "<table class=\"forumstab\">";
        table += "<tr>";
        table += "<th>#</th>";
        table += "<th>forum id</th>";
        table += "<th>name</th>";
        table += "<th>category</th>";
        table += "<th>users</th>";
        table += "<th>join</th>";
        table += "</tr>";
        table += "##TABLE-CONTENT##";
        table += "</table>";
        return table;
    }
}
